-- pe_mc.vhd
-- by Brittle 2009

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_misc.ALL;
USE ieee.std_logic_unsigned.ALL;
-- synthesis translate_off
Library XilinxCoreLib;
use ieee.std_logic_textio.all;
library std;
use std.textio.all;
-- synthesis translate_on
LIBRARY work;
use work.admxrc5t2_common.all;

ENTITY pe_mc IS
  GENERIC (
    cores : integer := 1);
  PORT (
    debug : out std_logic_vector(31 downto 0);
    -- global interface
    clk   : in  std_logic;
    rst   : in  std_logic;
    en    : in  std_logic;
    -- parameter interface
    n     : in  std_logic_vector(31 downto 0);
    i_ini : in  std_logic_vector(31 downto 0);
    i_end : in  std_logic_vector(31 downto 0);
    eps   : in  std_logic_vector(31 downto 0);
    -- ram interface
    rdy   : in  std_logic;
    req   : out std_logic;
    vld   : in  std_logic;
    addr  : out std_logic_vector(31 downto 0);
    p_x   : in  std_logic_vector(31 downto 0);
    p_y   : in  std_logic_vector(31 downto 0);
    p_z   : in  std_logic_vector(31 downto 0);
    p_m   : in  std_logic_vector(31 downto 0);
    -- control interface
    start : in  std_logic;
    done  : out std_logic;
    i_cnt : out std_logic_vector(31 downto 0);
    fifo_r: in  std_logic;
    a_x   : out reg_data_t(cores-1 downto 0);
    a_y   : out reg_data_t(cores-1 downto 0);
    a_z   : out reg_data_t(cores-1 downto 0));
END pe_mc;

ARCHITECTURE structural of pe_mc IS

  COMPONENT pe IS
    GENERIC (
      cores : integer := 1);
    PORT (
      debug : out std_logic_vector(31 downto 0);
      -- global interface
      clk   : in  std_logic;
      rst   : in  std_logic;
      en    : in  std_logic;
      -- parameter interface
      n     : in  std_logic_vector(31 downto 0);
      i_ini : in  std_logic_vector(31 downto 0);
      i_end : in  std_logic_vector(31 downto 0);
      eps   : in  std_logic_vector(31 downto 0);
      -- ram interface
      rdy   : in  std_logic;
      req   : out std_logic;
      vld   : in  std_logic;
      addr  : out std_logic_vector(31 downto 0);
      p_x   : in  std_logic_vector(31 downto 0);
      p_y   : in  std_logic_vector(31 downto 0);
      p_z   : in  std_logic_vector(31 downto 0);
      p_m   : in  std_logic_vector(31 downto 0);
      -- control interface
      start : in  std_logic;
      done  : out std_logic;
      i_cnt : out std_logic_vector(31 downto 0);
      fifo_r: in  std_logic;
      a_x   : out std_logic_vector(31 downto 0);
      a_y   : out std_logic_vector(31 downto 0);
      a_z   : out std_logic_vector(31 downto 0));
  END COMPONENT;

  signal i_ini_mc  : reg_data_t(cores-1 downto 0);
  signal rdy_mc    : std_logic;
  signal req_mc    : std_logic_vector(cores-1 downto 0);
  signal vld_mc    : std_logic_vector(cores-1 downto 0);
  signal addr_mc   : reg_data_t(cores-1 downto 0);
  signal done_mc   : std_logic_vector(cores-1 downto 0);
  signal i_cnt_mc  : reg_data_t(cores-1 downto 0);

  signal req_start : std_logic;
  signal vld_slt   : std_logic_vector(cores-1 downto 0);
  signal req_cnt   : std_logic_vector(3 downto 0);
  signal addr_reg  : std_logic_vector(31 downto 0);

  type state_type is (ST_IDLE, ST_IREQ, ST_IVLD, ST_FEED);
  signal fsm_state : state_type;
  signal fsm_cnt   : std_logic_vector(31 downto 0);

BEGIN

  ---------- core datapath ----------
  GEN_CORE: for id in 0 to cores-1 generate

    i_ini_mc(id) <= i_ini + id;

    U_pe : pe
      generic map (
        cores  => cores)
      port map (
        debug  => open   ,
        clk    => clk    ,
        rst    => rst    ,
        en     => en     ,

        n      => n  ,
        i_ini  => i_ini_mc(id),
        i_end  => i_end,
        eps    => eps,

        rdy    => rdy_mc,
        req    => req_mc(id),
        vld    => vld_mc(id),
        addr   => addr_mc(id),
        p_x    => p_x    ,
        p_y    => p_y    ,
        p_z    => p_z    ,
        p_m    => p_m    ,

        start  => start  ,
        done   => done_mc(id),
        fifo_r => fifo_r ,
        i_cnt  => i_cnt_mc(id),
        a_x    => a_x(id),
        a_y    => a_y(id),
        a_z    => a_z(id));

    vld_mc(id) <= vld when fsm_state = ST_FEED else vld and vld_slt(id);

  end generate;

  done <= done_mc(0);
  i_cnt <= i_cnt_mc(0);
  rdy_mc <= rdy when fsm_state = ST_FEED or fsm_state = ST_IDLE else '0';
  req <= req_mc(0) when fsm_state = ST_FEED else
         rdy when fsm_state = ST_IREQ else
         '0';
  addr <= addr_mc(0) when fsm_state = ST_FEED else addr_reg;

  ---------- memory interface ----------

  req_start <= req_mc(0) when fsm_state = ST_IDLE else '0';

  U_DATCNT : process (clk)
  begin
    if rising_edge(clk) then
      if rst = '1' or req_start = '1' then
        req_cnt <= (others => '0');
        vld_slt <= (cores-1 downto 1 => '0')&'1';
        addr_reg <= addr_mc(0);
      elsif vld = '1' and fsm_state = ST_IVLD then
        req_cnt <= req_cnt + 1;
        vld_slt <= vld_slt(cores-2 downto 0) & '0';
        addr_reg <= addr_reg + 1;
      end if;
    end if;
  end process;

  U_FSMCNT : process (clk)
  begin
    if rising_edge(clk) then
      if rst='1' or fsm_state = ST_IVLD then
        fsm_cnt <= (others => '0');
      elsif vld = '1' then
        fsm_cnt <= fsm_cnt + 1;
      end if;
    end if;
  end process;

  U_FSM : process (clk)
  begin
    if rising_edge(clk) then
      if rst='1' or start = '1' then
        fsm_state <= ST_IDLE;
      elsif en = '1' then
        case fsm_state is

          when ST_IDLE =>
            if req_start = '1' then
              fsm_state <= ST_IREQ;
            end if;

          when ST_IREQ =>
            if rdy = '1' then
              fsm_state <= ST_IVLD;
            end if;

          when ST_IVLD =>
            if vld = '1' then
              if req_cnt = cores-1 then
                fsm_state <= ST_FEED;
              else
                fsm_state <= ST_IREQ;
              end if;
            end if;

          when ST_FEED =>
            if fsm_cnt = n then
              fsm_state <= ST_IDLE;
            end if;

        end case;
      end if;
    end if;
  end process;

  -- Debug Signals
  debug(0) <= rdy;
  debug(1) <= vld;
  debug(2) <= req_start;
  debug(3) <= done_mc(0);

  debug(5 downto 4) <= "00" when fsm_state = ST_IDLE else
                       "01" when fsm_state = ST_IREQ else
                       "10" when fsm_state = ST_IVLD else
                       "11" when fsm_state = ST_FEED;

  debug(15 downto 6) <= vld_mc;

  debug(19 downto 16) <= req_cnt;

  debug(31 downto 20) <= fsm_cnt(11 downto 0);

END structural;
